import 'package:dio/dio.dart';
import 'http_exception.dart';
import 'http_response.dart';

class ZyHttpClient {
  late final Dio _dio;

  ZyHttpClient._internal() {
    _dio = Dio(BaseOptions(
      connectTimeout: Duration(seconds: 10),
      receiveTimeout: Duration(seconds: 10),
      headers: {'Content-Type': 'application/json'},
    ));

    _dio.interceptors.add(LogInterceptor(
      request: true,
      requestBody: true,
      responseBody: true,
      error: true,
    ));
  }

  static final ZyHttpClient instance = ZyHttpClient._internal();

  void setBaseUrl(String url) {
    _dio.options.baseUrl = url;
  }

  void setHeaders(Map<String, dynamic> headers) {
    _dio.options.headers.addAll(headers);
  }

  Future<HttpResponse<T>> get<T>({
    required String path,
    Map<String, dynamic>? query,
    required T Function(dynamic json) fromJson,
  }) async {
    try {
      final response = await _dio.get(path, queryParameters: query);
      return HttpResponse<T>.fromJson(response.data, fromJson);
    } catch (e) {
      throw _wrapError(e);
    }
  }

  Future<HttpResponse<T>> post<T>({
    required String path,
    Map<String, dynamic>? data,
    Map<String, dynamic>? query,
    required T Function(dynamic json) fromJson,
  }) async {
    try {
      final response =
          await _dio.post(path, data: data, queryParameters: query);
      return HttpResponse<T>.fromJson(response.data, fromJson);
    } catch (e) {
      throw _wrapError(e);
    }
  }

  Future<HttpResponse<T>> put<T>({
    required String path,
    Map<String, dynamic>? data,
    Map<String, dynamic>? query,
    required T Function(dynamic json) fromJson,
  }) async {
    try {
      final response = await _dio.put(path, data: data, queryParameters: query);
      return HttpResponse<T>.fromJson(response.data, fromJson);
    } catch (e) {
      throw _wrapError(e);
    }
  }

  Future<HttpResponse<T>> delete<T>({
    required String path,
    Map<String, dynamic>? data,
    Map<String, dynamic>? query,
    required T Function(dynamic json) fromJson,
  }) async {
    try {
      final response =
          await _dio.delete(path, data: data, queryParameters: query);
      return HttpResponse<T>.fromJson(response.data, fromJson);
    } catch (e) {
      throw _wrapError(e);
    }
  }

  HttpException _wrapError(Object error) {
    if (error is DioException) {
      return HttpException(
        error.message ?? 'Unknown error',
        code: error.response?.statusCode,
      );
    }
    return HttpException('Unexpected error: $error');
  }
}
